package com.lzq.mq.broker.core;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

@Slf4j
abstract class AbstractMMapFileModel {
    /**
     * MMap映射的文件路径
     */
    protected File file;
    /**
     * MMap映射的FileChannel
     */
    protected FileChannel fileChannel;
    /**
     * MMap映射的ByteBuffer
     */
    protected MappedByteBuffer writeByteBuffer;

    /**
     * 用于读元素的MMap
     */
    protected ByteBuffer readByteBuffer;

    /**
     * 存储consumeQueue文件的绝对路径和名称
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class FilePath {
        /**
         * 文件的名称
         */
        String fileName;
        /**
         * 文件的绝对路径
         */
        String filePath;
    }

    /**
     * 执行映射操作
     * @param filePath 文件绝对路径
     * @param startOffset 映射的起始位置
     * @param mappedSize 映射的尺寸
     */
    protected final void doMMap(String filePath, int startOffset, int mappedSize, int pos) throws IOException {

        this.file = new File(filePath);
        if (!file.exists()) {
            // 确保父目录存在
            File parentDir = file.getParentFile();
            if (parentDir != null && !parentDir.exists()) {
                parentDir.mkdirs();
            }
            file.createNewFile();
            log.warn("MMap文件不存在, 重新创建创建文件: {}", filePath);
        }
        this.fileChannel = new RandomAccessFile(file, "rw").getChannel();
        this.writeByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, startOffset, mappedSize);

        //从指定位置开始追加写入
        this.readByteBuffer = writeByteBuffer.slice();
        this.writeByteBuffer.position(pos);
    }

    /**
     * 读取内容
     * @param offset 偏移量
     * @param size 读取的尺寸
     * @return 读取的内容
     */
    public final byte[] read(Integer offset, int size) {

        // 为什么还要slice?
        // 使多线程不会出现冲突！
        ByteBuffer readBuffer = readByteBuffer.slice();
        readBuffer.position(offset);
        byte[] content = new byte[size];
        readBuffer.get(content);
        return content;
    }
}
